#!/bin/bash
#
# Copyright(c) 2012-2021 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#

# The line below specified that line under it should be used as the test's short description when launching test via run_tests script.
# The text should not be longer than 80 chars - if it is, the script will strip addititonal characters
# DESCRIPTION Change cache mode while IO is serviced

# USE_IN_NIGHTLY

# Standard beginning for every test - get the main tests directory and
# link the cas_lib file for CAS API, then use "start_test $*" to pass params
# and do other necessary checks and setup
TESTS_DIR="$(dirname $0)/../"
. $TESTS_DIR/cas_lib
start_test $*

TEST_JOBS_NR=8
TEST_JOBS_FILES_NR=100
TEST_JOBS_FILES_SIZE=1M

TEST_JOBS_FILE=/tmp/cas.test.
TEST_JOBS_RESULT=/tmp/cas.result

TEST_JOBS_PIDS=
TEST_JOB_SUSPEND_PID=
TEST_JOBS_TIME=20

TEST_CORE_DEVICE_SIZE=${TEST_JOBS_NR}*${TEST_JOBS_FILES_NR}*$(get_bytes ${TEST_JOBS_FILES_SIZE})+$(get_bytes "3G")
let TEST_CORE_DEVICE_SIZE=$TEST_CORE_DEVICE_SIZE
let TEST_CORE_DEVICE_SIZE=$TEST_CORE_DEVICE_SIZE/$(get_bytes "G")

TEST_CORE_DEVICE_SIZE="${TEST_CORE_DEVICE_SIZE}G"
TEST_CACHE_DEVICE_SIZE=400M

#param1 - Job ID
cache_suspend_job() {
    local L_ITER=2
    local L_JOB_ID=$1
    local L_FILE=""
    local L_FILE_CAS=""
    local L_RESULT="0"
    local L_FILE_RESULT="${TEST_JOBS_RESULT}-${L_JOB_ID}"

    echo $L_RESULT > $L_FILE_RESULT

    while [ true ]
    do
    test_log_trace "Test job $L_JOB_ID is running"

        for (( I=0; I<$TEST_JOBS_FILES_NR; I=I+1 ))
        do
            # Creat test files
            L_FILE=${TEST_JOBS_FILE}${L_JOB_ID}-${I}
            L_FILE_CAS="${MOUNTPOINT}-1-1/$(basename $L_FILE)"

            rm -f "$L_FILE_CAS"
            rm -f "$L_FILE"

            dd if=/dev/urandom of="$L_FILE" bs=$TEST_JOBS_FILES_SIZE count=1 &>/dev/null

            #copy test file
            cp $L_FILE $L_FILE_CAS
            if [ $? != 0 ]
            then
                test_log_trace "Copy ERROR, Job ID is $L_JOB_ID"
                L_RESULT="-1"
                break
            fi

            sync && echo 3 > /proc/sys/vm/drop_caches

            #compare copied files with orginal
            cmp $L_FILE $L_FILE_CAS
            if [ $? != 0 ]
            then
                test_log_trace "Data Integrity ERROR, Job ID is $L_JOB_ID"
                L_RESULT="-1"
                break
            fi

            sync && echo 3 > /proc/sys/vm/drop_caches
        done

        if [ "0" != "L_RESULT" ]
        then
            break
        fi

        for (( I=0; I<$TEST_JOBS_FILES_NR; I=I+1 ))
        do
            # Check md5 sums
            L_FILE=${TEST_JOBS_FILE}${L_JOB_ID}-${I}
            L_FILE_CAS="${MOUNTPOINT}-1-1/$(basename $L_FILE)"

            L_FILE_MD5=$(md5sum -b $L_FILE | awk '{ print $1 }')
            L_FILE_CAS_MD5=$(md5sum -b $L_CAS_FILE | awk '{ print $1 }')

            if [ "$L_FILE_MD5" != "$L_FILE_CAS_MD5" ]
            then
                test_log_trace "MD5 sum ERROR, Job ID is $L_JOB_ID"
                L_RESULT="-1"
                break
            fi
        done

        let L_ITER=${L_ITER}-1
        if [ 0 -eq $L_ITER ]
        then
             break;
        fi

        if [ "0" != "L_RESULT" ]
        then
            break
        fi
    done

    #
    # Clean after tests
    #
    for (( I=0; I<$TEST_JOBS_FILES_NR; I=I+1 ))
    do
        # Remove test file
        L_FILE=${TEST_JOBS_FILE}${L_JOB_ID}-${I}
        rm -f $L_FILE
    done

    echo $L_RESULT > $L_FILE_RESULT
}

#param1 - Flushing {YES - Perform Flushing during suspending cache, NO}
cache_suspend() {
    local L_CACHE_MODES=("wt" "wb" "wa" "pt" "wa" "wo")
    local L_CACHE_MODE
    local L_CACHE_MODE_NR

    while [ true ]
    do
        sleep 1

        L_CACHE_MODE_NR=${RANDOM}
        let L_CACHE_MODE_NR=$L_CACHE_MODE_NR%${#L_CACHE_MODES[@]}

        L_CACHE_MODE=${L_CACHE_MODES[$L_CACHE_MODE_NR]}

        test_log_trace "Switching to $L_CACHE_MODE mode"
        DONT_FAIL_ON_ERROR_OPTION="YES"
        CACHE_ID_OPTION="1" CACHE_MODE_OPTION="$L_CACHE_MODE" set_cache_mode
    done
}

cache_suspend_start_jobs () {
    local L_JOB_ID=$1

    for (( ID=0; ID<$TEST_JOBS_NR; ID=ID+1 ))
    do
        cache_suspend_job "${ID}" &
        TEST_JOBS[$ID]=$!
    done

    cache_suspend &
    TEST_JOB_SUSPEND_PID=$!

    return 0
}

cache_suspend_wait() {
    for (( ID=0; ID<$TEST_JOBS_NR; ID=ID+1 ))
    do
        wait ${TEST_JOBS[$ID]}
    done
    kill $TEST_JOB_SUSPEND_PID
}

cache_suspend_result() {
    local L_RESULT
    local L_FILE_RESULT=""

    for (( ID=0; ID<$TEST_JOBS_NR; ID=ID+1 ))
    do
        L_FILE_RESULT="${TEST_JOBS_RESULT}-${ID}"
        L_RESULT=$(cat $L_FILE_RESULT)

        if [ "0" != $L_RESULT ]
        then
            test_log_trace "Test job FAILURE, ID is $ID"
            return 1
        fi
    done

    return 0
}

#param1 - Metadata Varaint
#param2 - File system type
cache_suspend_i() {
    local L_RESULT=0

    cache_suspend_start_jobs

    cache_suspend_wait

    cache_suspend_result
    if [ $? != 0 ]
    then
        result=-1
        test_log_trace "FAILURE"
    fi

    if [ 0 -eq $L_RESULT ]
    then
        return 0
    else
        return 1
    fi
}

test_log_start

test_log_trace "Cache size is ${TEST_CACHE_DEVICE_SIZE}, Core size is ${TEST_CORE_DEVICE_SIZE}"

CACHE_LINE_SIZE="all"
NUMBER_OF_CORE_PARTITIONS="1"
NUMBER_OF_CACHE_PARTITIONS="1"
MAKE_FILE_SYSTEM="all"
iteration cache_suspend_i


test_log_stop

# Always return 0 at the end of the test - if at any point something has failed
# in the API functions, test will end and return a proper result.
# If you need to check other things during the test and end the test earlier, you
# should end the test using "end_test $retval" function
end_test 0
